package com.syyo.gulimall.search.thread;

import java.util.concurrent.*;

/**
 * @ author: wang
 * @ date: 2021/4/2 17:01
 * @ Description:
 */
public class ThreadTest {

    public static ExecutorService executor = Executors.newFixedThreadPool(10);


    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main方法开始了");
        /**
         * runAsync 异步没有返回值
         */
      /*  CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("Thread 当前线程： " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Thread 运行结果: " + i);

        }, executor);*/

        /**
         * 方法完成后的感知
         * supplyAsync 异步有返回值
         * whenComplete 只能得到异常信息
         * exceptionally 可以得到异常信息，并且可以返回自定义值
         */
     /*   CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("Thread 当前线程： " + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("Thread 运行结果: " + i);
            return i;
        },executor).whenComplete((res,excption)->{
            // whenComplete 只能得到异常信息
            System.out.println("异步任务成功");
            System.out.println(res);
            System.out.println(excption);
        }).exceptionally((err)->{
            // exceptionally 可以得到异常信息，并且可以返回自定义值
            return 10;
        });*/

        /**
         * 方法完成后的处理
         *
         * handle:异步方法执行完的后续处理
         */
  /*      CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("Thread 当前线程： " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Thread 运行结果: " + i);
            return i;
        },executor).handle((res,excption)->{
            if (res != null){
                return res*2;
            }
            if (excption != null){
                return 0;
            }
            System.out.println("异步任务成功");
            System.out.println(res);
            System.out.println(excption);
            return 0;
        });*/


        /**
         * 线程串行化
         * 方法带Async是用新的线程来执行，不带Async是原来的线程来执行
         * thenRunAsync 不能获取到上一步的获取结果
         * thenAcceptAsync 可以获取到上一步的结果
         * thenApplyAsync 可以获取到上一步的结果,并且可以自定义返回值
         */
    /*    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Thread 当前线程： " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Thread 运行结果: " + i);
            return i;
        },executor).thenApplyAsync((res)->{
            System.out.println("任务2 启动了: "+res);
            return 0;
        },executor);
        // get() 是一个阻塞方法
        Integer integer = future1.get();*/


        /**
         * 两个任务都完成，才执行
         * 方法带Async是用新的线程来执行，不带Async是原来的线程来执行
         * runAfterBothAsync 不能获取到上一步的获取结果
         * thenAcceptBothAsync 可以获取到上一步的结果
         * thenCombineAsync 可以获取到上一步的结果,并且可以自定义返回值
         */
//        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1 当前线程： " + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("任务1 运行结果: " + i);
//            return i;
//        },executor);
//
//        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务2 当前线程： " + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("任务2 运行结果: " + i);
//            return "hello";
//        },executor);

//        future01.runAfterBothAsync(future02,()->{
//            System.out.println("任务3 开始: ");
//        },executor);

//        future01.thenAcceptBothAsync(future02,(f1,f2)->{
//            System.out.println("任务3 开始: ");
//            System.out.println("之前的结果: "+f1+"----"+f2);
//        },executor);

//        CompletableFuture<String> future3 = future01.thenCombineAsync(future02, (f1, f2) -> {
//            System.out.println("任务3 开始: ");
//            return f1 + "====" + f2;
//        }, executor);
//        String s = future3.get();


        /**
         * 两个任务中有一个完成，就执行
         * 方法带Async是用新的线程来执行，不带Async是原来的线程来执行
         * runAfterEither 不能获取到上一步的获取结果
         * acceptEitherAsync 可以获取到上一步的结果
         * applyToEither 可以获取到上一步的结果,并且可以自定义返回值
         */

        /**
         * 多任务组合
         * 方法带Async是用新的线程来执行，不带Async是原来的线程来执行
         * allOf 不能获取到上一步的获取结果
         * anyOf 可以获取到上一步的结果
         * applyToEither 可以获取到上一步的结果,并且可以自定义返回值
         */
        CompletableFuture<String> future04 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "sku_img";
        });
        CompletableFuture<String> future05 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性信息");
            return "黑色+256G";
        });
        CompletableFuture<String> future06 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍信息");
            return "华为";
        });

//        CompletableFuture<Void> future = CompletableFuture.allOf(future04, future05, future06);
        CompletableFuture<Object> future = CompletableFuture.anyOf(future04, future05, future06);
        future.get();

        System.out.println("main方法结束了:" + future.get());
    }


    /**
     * 1.继承 Thread
     * 2.实现 Runnable接口
     * 3.实现 Callable 接口 + FutureTask（可以拿到返回接口，可以处理异常）
     * 4.线程池
     * <p>
     * 区别：
     * 1,2 不能得到返回值，3 可以获取返回值
     * 1,2,3 不能控制资源
     * 4 最优
     */
    public static void thread(String[] args) throws ExecutionException, InterruptedException {

        System.out.println("main方法开始了");
//        Thread01 thread01 = new Thread01();
//        thread01.start();

//        Runable02 runable02 = new Runable02();
//        new Thread(runable02).start();

//        FutureTask<Integer> futureTask = new FutureTask<>(new Callable03());
//        new Thread(futureTask).start();
//        // 等待线程执行完成，获取返回结果  阻塞等待
//        Integer integer = futureTask.get();

        // 使用线程池
        executor.execute(new Runable02());

        /**
         * int corePoolSize, 核心线程数，只要线程池不销毁，就一直存在
         * int maximumPoolSize, 最大线程数量，控制资源并发
         * long keepAliveTime, 存活时间，如果当前线程数量大于核心数量
         *      释放空闲的线程（maximumPoolSize - corePoolSize），只要线程空闲时间大于这个值就会释放
         * TimeUnit unit, 时间单位
         * BlockingQueue<Runnable> workQueue, 阻塞队列，超过的任务会放在队列里等待，只要有线程空闲，就会去队列里取新的任务执行,默认是Integer的最大值
         * ThreadFactory threadFactory, 线程工程
         * RejectedExecutionHandler handler 如果队列满了，按照我们指定的拒绝策略来执行拒绝任务
         *
         * 工作流程
         *      1.线程池创建，准备好core线程，接收任务
         *      2.core线程满了，就将任务放到队列里
         *      3.如果workQueue阻塞队列满了，就会开启新的线程来执行任务（不能超过max线程数）
         *      4.如果max线程满了，就会使用指定的handler拒绝策略拒绝任务
         *      5.max线程数都执行完了，有很多空闲的，在指定的时间释放空闲的线程，释放后剩下的线程不能小于core线程数
         *
         *
         *
         *  面试
         */
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        Executors.newCachedThreadPool();// core是0，所有都可回收
        Executors.newFixedThreadPool(10);// 固定大小，core=max
        Executors.newScheduledThreadPool(10);// 定时任务线程池
        Executors.newSingleThreadExecutor(); // 单例线程池

        System.out.println("main方法结束了");
    }


    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("Thread 当前线程： " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Thread 运行结果: " + i);
        }
    }

    public static class Runable02 implements Runnable {

        @Override
        public void run() {
            System.out.println("Runable 当前线程： " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Runable 运行结果: " + i);
        }
    }

    public static class Callable03 implements Callable<Integer> {
        @Override
        public Integer call() {
            System.out.println("Callable 当前线程： " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Callable 运行结果: " + i);
            return i;
        }
    }

}
